/*
 *   This program is free software; you can redistribute it and/or modify
 *   it under the terms of the GNU General Public License as published by
 *   the Free Software Foundation; either version 2 of the License, or
 *   (at your option) any later version.
 *
 *   This program is distributed in the hope that it will be useful,
 *   but WITHOUT ANY WARRANTY; without even the implied warranty of
 *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *   GNU General Public License for more details.
 *
 *
 *   版权所有  2014-2015 成都星锐蓝海网络科技有限公司
 *   商业许可请联系  +86-18682011860    QQ:66442834
 *   
 */

#ifndef __XYZ_STR_H__
#define __XYZ_STR_H__

#include <ctype.h>
#include <string.h>
#include <stdlib.h>
#include "xyz_int.h"

typedef struct xyz_str {
	xyz_sli_t len;
	xyz_u8_t *data;
} xyz_str_t;


#define xyz_string(str, len)	{ len, (xyz_u8_t *)str }
#define xyz_null_string         { 0, NULL }
#define xyz_str_set(str, text, size) do{(str)->len=size;(str)->data=(xyz_u8_t *)text;}while(0)
#define xyz_str_null(str)	xyz_str_set(str, NULL, 0)

#define xyz_str_1cmp(s, c)	((s)[0] == c)
#define xyz_str_2cmp(s, c0, c1)	(((s)[0] == c0) && ((s)[1] == c1))
#define xyz_str_3cmp(s, c0, c1, c2)	(((s)[0] == c0) && ((s)[1] == c1),  && ((s)[2] == c2))
#define xyz_str_4cmp(s, c0, c1, c2, c3)	(((s)[0] == c0) && ((s)[1] == c1) && ((s)[2] == c2)  && ((s)[3] == c3))
#define xyz_str_5cmp(s, c0, c1, c2, c3, c4)	(((s)[0] == c0) && ((s)[1] == c1) && ((s)[2] == c2) && ((s)[3] == c3) && ((s)[4] == c4))

#define xyz_str_is_valid(str) (((str)->data) && (((str)->len) > 0))

//  比较两个字符串是否相等
static inline int xyz_str_cmp(xyz_str_t *s1, xyz_str_t *s2)
{
	return ((s1->len == s2->len) ? ((s1->data == s2->data) ? 0 : memcmp(s1->data, s2->data, s1->len)) : -1);
}

//  比较字符串的前len长度是否相等
static inline int xyz_str_ncmp(xyz_str_t *s1, xyz_str_t *s2, xyz_sli_t len)
{
	return (s1->len >= len ? ( s2->len >= len ? memcmp(s1->data, s2->data, len) : -1 ) : -1);
}

//  小心！小心！该函数可能导致内存data指向的内存无法释放
static inline int xyz_str_offset(xyz_str_t *s, xyz_sli_t off)
{
	return (s->len - off >= 0 ? (s->len -= off, s->data += off, 0) : -1);
}

xyz_str_t *xyz_str_malloc(xyz_sli_t size);

xyz_str_t *xyz_str_malloc_text(const char *text, xyz_sli_t size);

xyz_str_t *xyz_str_malloc_i32(xyz_i32_t n);

xyz_str_t *xyz_str_malloc_u32(xyz_u32_t n);

xyz_str_t *xyz_str_malloc_i64(xyz_i64_t n);

xyz_str_t *xyz_str_malloc_u64(xyz_u64_t n);

static inline void xyz_str_free(xyz_str_t *s)
{
	if(s) { free(s); }
}

//  转换为小写字符串
void xyz_str_lower(xyz_u8_t *s, xyz_sli_t len);

//  跳过空白字符'\f' '\n' '\r' '\t' '\v'
void xyz_str_upper(xyz_u8_t *s, xyz_sli_t len);

//  跳过空白字符
xyz_sli_t xyz_str_skip_spaces(const xyz_u8_t *s, xyz_sli_t len);

//  获取数字开始位置
xyz_sli_t xyz_str_skip_to_digit(const xyz_u8_t *s, xyz_sli_t len);

//  获取不是数字开始位置
xyz_sli_t xyz_str_skip_to_undigit(const xyz_u8_t *s, xyz_sli_t len);

//  获取十六进制数字开始位置
xyz_sli_t xyz_str_skip_to_hex(const xyz_u8_t *s, xyz_sli_t len);

//  获取不是十六进制数字开始位置
xyz_sli_t xyz_str_skip_to_unhex(const xyz_u8_t *s, xyz_sli_t len);

//  获取可显示字符开始位置
xyz_sli_t xyz_str_skip_to_print(const xyz_u8_t *s, xyz_sli_t len);

//  获取不可显示字符开始位置
xyz_sli_t xyz_str_skip_to_unprint(const xyz_u8_t *s, xyz_sli_t len);

//  获取可打印字符开始位置
xyz_sli_t xyz_str_skip_to_print(const xyz_u8_t *s, xyz_sli_t len);

//  获取不可打印字符开始位置
xyz_sli_t xyz_str_skip_to_unprint(const xyz_u8_t *s, xyz_sli_t len);

//  获取指定字符第一次出现的位置
xyz_sli_t xyz_str_chr(const xyz_u8_t *s, xyz_sli_t len, xyz_u8_t ch);

//  获取指定字符最后一次出现的位置
xyz_sli_t xyz_str_rchr(const xyz_u8_t *s, xyz_sli_t len, xyz_u8_t ch);

//  获取字符串s2在字符串s1中第一次开始的位置
xyz_sli_t xyz_str_str(const xyz_u8_t *s1, xyz_sli_t len1, const xyz_u8_t *s2, xyz_sli_t len2);

//  获取字符串s2在字符串s1中最后一次开始的位置
xyz_sli_t xyz_str_rstr(const xyz_u8_t *s1, xyz_sli_t len1, const xyz_u8_t *s2, xyz_sli_t len2);

//  忽略大消息比较两个字符串
int xyz_str_casecmp(const xyz_u8_t *s1, xyz_sli_t len1, const xyz_u8_t *s2, xyz_sli_t len2);

//  忽略大消息比较两个字符串前n个字符
int xyz_str_ncasecmp(const xyz_u8_t *s1, xyz_sli_t len1, const xyz_u8_t *s2, xyz_sli_t len2, xyz_sli_t n);

//  BKDR字符串哈希计算
xyz_uli_t xyz_str_BKDR_hash(const xyz_u8_t *in, xyz_sli_t len, xyz_uli_t seed, xyz_uli_t hash);


#endif /* __XYZ_STR_H__ */
